home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / animationplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-01  |  45.5 KB  |  1,986 lines

  1. /*
  2.  * Animation Playback plug-in version 0.98.8
  3.  *
  4.  * (c) Adam D. Moss : 1997-2000 : adam@gimp.org : adam@foxbox.org
  5.  *
  6.  *
  7.  * This is part of the GIMP package and is released under the GNU
  8.  * Public License.
  9.  */
  10.  
  11. /*
  12.  * REVISION HISTORY:
  13.  *
  14.  * 2000-08-30 : version 0.98.8
  15.  *              Default frame timing is now 100ms instead of 125ms.
  16.  *
  17.  * 2000-06-05 : version 0.98.7
  18.  *              Fix old bug which could cause errors in evaluating the
  19.  *              final pixel of each composed layer.
  20.  *
  21.  * 2000-01-13 : version 0.98.6
  22.  *              Looser parsing of (XXXXX) layer-name tags
  23.  *
  24.  * 98.07.27 : version 0.98.5
  25.  *            UI tweaks, fix for pseudocolor displays w/gdkrgb.
  26.  *
  27.  * 98.07.20 : version 0.98.4
  28.  *            User interface improvements.
  29.  *
  30.  * 98.07.19 : version 0.98.2
  31.  *            Another speedup for some kinds of shaped animations.
  32.  *
  33.  * 98.07.19 : version 0.98.0
  34.  *            Adapted to use GDKRGB (from recent GTK >= 1.1) if
  35.  *            available - good speed and reliability improvement.
  36.  *            Plus some minor tweaks.
  37.  *
  38.  * 98.04.28 : version 0.94.2
  39.  *            Fixed a time-parsing bug.
  40.  *
  41.  * 98.04.05 : version 0.94.0
  42.  *            Improved performance and removed flicker when shaped.
  43.  *            Shaped mode also works with RGB* images now.
  44.  *            Fixed some longstanding potential visual debris.
  45.  *
  46.  * 98.04.04 : version 0.92.0
  47.  *            Improved responsiveness and performance for the new
  48.  *            shaped-animation mode.  Still some flicker.
  49.  *
  50.  * 98.04.02 : version 0.90.0
  51.  *            EXPERIMENTAL wackyness - try dragging the animation
  52.  *            out of the plugin dialog's preview box...
  53.  *            (only works on non-RGB* images for now)
  54.  *
  55.  * 98.03.16 : version 0.85.0
  56.  *            Implemented some more rare opaque/alpha combinations.
  57.  *
  58.  * 98.03.15 : version 0.84.0
  59.  *            Tried to clear up the GTK object/cast warnings.  Only
  60.  *            partially successful.  Could use some help.
  61.  *
  62.  * 97.12.11 : version 0.83.0
  63.  *            GTK's timer logic changed a little... adjusted
  64.  *            plugin to fit.
  65.  *
  66.  * 97.09.16 : version 0.81.7
  67.  *            Fixed progress bar's off-by-one problem with
  68.  *            the new timing.  Fixed erroneous black bars which
  69.  *            were sometimes visible when the first frame was
  70.  *            smaller than the image itself.  Made playback
  71.  *            controls inactive when image doesn't have multiple
  72.  *            frames.  Moved progress bar above control buttons,
  73.  *            it's less distracting there.  More cosmetic stuff.
  74.  *
  75.  * 97.09.15 : version 0.81.0
  76.  *            Now plays INDEXED and GRAY animations.
  77.  *
  78.  * 97.09.15 : version 0.75.0
  79.  *            Next frame is generated ahead of time - results
  80.  *            in more precise timing.
  81.  *
  82.  * 97.09.14 : version 0.70.0
  83.  *            Initial release.  RGB only.
  84.  */
  85.  
  86. /*
  87.  * BUGS:
  88.  *  Gets understandably upset if the source image is deleted
  89.  *    while the animation is playing.  Decent solution welcome.
  90.  *
  91.  *  In shaped mode, the shaped-window's mask and its pixmap contents
  92.  *    can get way out of sync (specifically, the mask changes but
  93.  *    the contents are frozen).  Starvation of GTK's redrawing thread?
  94.  *    How do I fix this?
  95.  *
  96.  *  Any more?  Let me know!
  97.  */
  98.  
  99. /*
  100.  * TODO:
  101.  *  pdb interface - should we bother?
  102.  *
  103.  *  speedups (caching?  most bottlenecks seem to be in pixelrgns)
  104.  *    -> do pixelrgns properly!
  105.  *
  106.  *  write other half of the user interface (default timing, disposal &c)
  107.  */
  108.  
  109. #include "config.h"
  110.  
  111. #include <stdlib.h>
  112. #include <stdio.h>
  113. #include <string.h>
  114. #include <ctype.h>
  115.  
  116. #include <gtk/gtk.h>
  117.  
  118. #ifndef GDK_WINDOWING_WIN32
  119. # include <gdk/gdkx.h>
  120. #else
  121. # if GTK_MAJOR_VERSION == 1 && GTK_MINOR_VERSION == 3 && GTK_MICRO_VERSION == 0
  122. /* The gtk+-1.3.0-win32-production distribution has an unsuitable gdkwin32.h */
  123. #  include <windows.h>
  124. #  define GDK_ROOT_WINDOW() ((guint32) HWND_DESKTOP)
  125. GdkPixmap *gdk_pixmap_foreign_new (guint32 anid);
  126. # else
  127. #  include <gdk/gdkwin32.h>
  128. # endif
  129. #endif
  130.  
  131. #include <libgimp/gimp.h>
  132. #include <libgimp/gimpui.h>
  133.  
  134. #include "libgimp/stdplugins-intl.h"
  135.  
  136.  
  137. /* Test for GTK1.2-style gdkrgb code, else use old 'preview' code. */
  138. #ifdef __GDK_RGB_H__
  139. #define RAPH_IS_HOME yep
  140. /* Dithertype for animated GIFs */
  141. #define DITHERTYPE GDK_RGB_DITHER_NORMAL
  142. #endif
  143.  
  144. /* #define I_AM_STUPID yesiam */
  145.  
  146. typedef enum
  147. {
  148.   DISPOSE_UNDEFINED = 0x00,
  149.   DISPOSE_COMBINE   = 0x01,
  150.   DISPOSE_REPLACE   = 0x02
  151. } DisposeType;
  152.  
  153.  
  154.  
  155. /* Declare local functions. */
  156. static void query (void);
  157. static void run   (gchar   *name,
  158.            gint     nparams,
  159.            GimpParam  *param,
  160.            gint    *nreturn_vals,
  161.            GimpParam **return_vals);
  162.  
  163. static        void do_playback        (void);
  164.  
  165. static gint window_delete_callback    (GtkWidget *widget,
  166.                        GdkEvent  *event,
  167.                        gpointer   data);
  168. static void window_close_callback     (GtkWidget *widget,
  169.                        gpointer   data);
  170. static void playstop_callback         (GtkWidget *widget,
  171.                        gpointer   data);
  172. static void rewind_callback           (GtkWidget *widget,
  173.                        gpointer   data);
  174. static void step_callback             (GtkWidget *widget,
  175.                        gpointer   data);
  176. #ifdef RAPH_IS_HOME
  177. static void repaint_sda               (GtkWidget *darea,
  178.                        gpointer data);
  179. static void repaint_da                (GtkWidget *darea,
  180.                        gpointer data);
  181. #endif
  182.  
  183. static void         render_frame        (gint32 whichframe);
  184. static void         show_frame          (void);
  185. static void         total_alpha_preview (guchar* ptr);
  186. static void         init_preview_misc   (void);
  187.  
  188.  
  189. /* tag util functions*/
  190. static         int parse_ms_tag        (const char *str);
  191. static DisposeType parse_disposal_tag  (const char *str);
  192. static DisposeType get_frame_disposal  (const guint whichframe);
  193. static     guint32 get_frame_duration  (const guint whichframe);
  194. static int is_disposal_tag (const char *str,
  195.                 DisposeType *disposal,
  196.                 int *taglength);
  197. static int is_ms_tag (const char *str,
  198.               int *duration,
  199.               int *taglength);
  200.  
  201.  
  202.  
  203.  
  204. GimpPlugInInfo PLUG_IN_INFO =
  205. {
  206.   NULL,  /* init_proc  */
  207.   NULL,  /* quit_proc  */
  208.   query, /* query_proc */
  209.   run,   /* run_proc   */
  210. };
  211.  
  212.  
  213. /* Global widgets'n'stuff */
  214. static guchar    *preview_data;
  215. #ifdef RAPH_IS_HOME
  216. static GtkWidget *drawing_area = NULL;
  217. static GtkWidget *shape_drawing_area = NULL;
  218. static guchar    *shape_drawing_area_data = NULL;
  219. static guchar    *drawing_area_data = NULL;
  220. #else
  221. static GtkPreview* preview = NULL;
  222. #endif
  223. static GtkProgressBar *progress;
  224. static guint           width, height;
  225. static guchar         *preview_alpha1_data;
  226. static guchar         *preview_alpha2_data;
  227. static gint32          image_id;
  228. static gint32          total_frames;
  229. static guint           frame_number;
  230. static gint32         *layers;
  231. static GimpDrawable      *drawable;
  232. static gboolean        playing = FALSE;
  233. static gint            timer = 0;
  234. static GimpImageBaseType      imagetype;
  235. static guchar         *palette;
  236. static gint            ncolours;
  237. static GtkWidget      *psbutton;
  238.  
  239. /* for shaping */
  240. static gchar      *shape_preview_mask;
  241. static GtkWidget  *shape_window;
  242. #ifdef RAPH_IS_HOME
  243. #else
  244. static GtkWidget  *shape_fixed;
  245. static GtkPreview *shape_preview;
  246. static GdkPixmap  *shape_pixmap;
  247. #endif
  248. typedef struct _cursoroffset {gint x,y;} CursorOffset;
  249. static gint        shaping = 0;
  250. static GdkWindow  *root_win = NULL;
  251.  
  252.  
  253. MAIN ()
  254.  
  255. static void 
  256. query (void)
  257. {
  258.   static GimpParamDef args[] =
  259.   {
  260.     { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive" },
  261.     { GIMP_PDB_IMAGE,    "image",    "Input image" },
  262.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)" }
  263.   };
  264.   static gint nargs = sizeof (args) / sizeof (args[0]);
  265.  
  266.   gimp_install_procedure ("plug_in_animationplay",
  267.               "This plugin allows you to preview a GIMP layer-based animation.",
  268.               "",
  269.               "Adam D. Moss <adam@gimp.org>",
  270.               "Adam D. Moss <adam@gimp.org>",
  271.               "1997, 1998...",
  272.               N_("<Image>/Filters/Animation/Animation Playback..."),
  273.               "RGB*, INDEXED*, GRAY*",
  274.               GIMP_PLUGIN,
  275.               nargs, 0,
  276.               args, NULL);
  277. }
  278.  
  279. static void 
  280. run (gchar   *name, 
  281.      gint     n_params, 
  282.      GimpParam  *param, 
  283.      gint    *nreturn_vals,
  284.      GimpParam **return_vals)
  285. {
  286.   static GimpParam values[1];
  287.   GimpRunModeType run_mode;
  288.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  289.  
  290.   *nreturn_vals = 1;
  291.   *return_vals = values;
  292.  
  293.   run_mode = param[0].data.d_int32;
  294.  
  295.   if (run_mode == GIMP_RUN_NONINTERACTIVE) 
  296.     {
  297.       if (n_params != 3) 
  298.     {
  299.       status = GIMP_PDB_CALLING_ERROR;
  300.     }
  301.       INIT_I18N();
  302.     } 
  303.   else 
  304.     {
  305.       INIT_I18N_UI();
  306.     }
  307.  
  308.   if (status == GIMP_PDB_SUCCESS) 
  309.     {
  310.       image_id = param[1].data.d_image;
  311.       
  312.       do_playback();
  313.       
  314.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  315.     gimp_displays_flush();
  316.     }
  317.  
  318.   values[0].type = GIMP_PDB_STATUS;
  319.   values[0].data.d_status = status;
  320. }
  321.  
  322.  
  323.  
  324. /*
  325. static int
  326. parse_ms_tag (char *str)
  327. {
  328.   gint sum = 0;
  329.   gint offset = 0;
  330.   gint length;
  331.  
  332.   length = strlen(str);
  333.  
  334. find_another_bra:
  335.  
  336.   while ((offset<length) && (str[offset]!='('))
  337.     offset++;
  338.   
  339.   if (offset>=length)
  340.     return(-1);
  341.  
  342.   if (!isdigit(str[++offset]))
  343.     goto find_another_bra;
  344.  
  345.   do
  346.     {
  347.       sum *= 10;
  348.       sum += str[offset] - '0';
  349.       offset++;
  350.     }
  351.   while ((offset<length) && (isdigit(str[offset])));  
  352.  
  353.   if (length-offset <= 2)
  354.     return(-3);
  355.  
  356.   if ((toupper(str[offset]) != 'M') || (toupper(str[offset+1]) != 'S'))
  357.     return(-4);
  358.  
  359.   return (sum);
  360. }
  361.  
  362.  
  363. static DisposeType
  364. parse_disposal_tag (char *str)
  365. {
  366.   gint offset = 0;
  367.   gint length;
  368.  
  369.   length = strlen(str);
  370.  
  371.   while ((offset+9)<=length)
  372.     {
  373.       if (strncmp(&str[offset],"(combine)",9)==0) 
  374.     return(DISPOSE_COMBINE);
  375.       if (strncmp(&str[offset],"(replace)",9)==0) 
  376.     return(DISPOSE_REPLACE);
  377.       offset++;
  378.     }
  379.  
  380.   return (DISPOSE_UNDEFINED);
  381. }*/
  382.  
  383.  
  384. static void
  385. reshape_from_bitmap (gchar* bitmap)
  386. {
  387.   GdkBitmap *shape_mask;
  388.   static gchar *prev_bitmap = NULL;
  389.  
  390.   if ((!prev_bitmap) ||
  391.       (memcmp(prev_bitmap, bitmap, (width*height)/8 +height)))
  392.     {
  393.       shape_mask = gdk_bitmap_create_from_data(shape_window->window,
  394.                            bitmap,
  395.                            width, height);
  396.       gtk_widget_shape_combine_mask (shape_window, shape_mask, 0, 0);
  397.       gdk_bitmap_unref (shape_mask);
  398.  
  399.       if (!prev_bitmap)
  400.     {
  401.       prev_bitmap = g_malloc ((width*height)/8 +height);
  402.     }
  403.       memcpy (prev_bitmap, bitmap, (width*height)/8 +height);
  404.     }
  405. }
  406.  
  407.  
  408. static void
  409. shape_pressed (GtkWidget      *widget, 
  410.            GdkEventButton *event)
  411. {
  412.   CursorOffset *p;
  413.  
  414.   /* ignore double and triple click */
  415.   if (event->type != GDK_BUTTON_PRESS)
  416.     return;
  417.  
  418.   p = gtk_object_get_user_data (GTK_OBJECT(widget));
  419.   p->x = (int) event->x;
  420.   p->y = (int) event->y;
  421.  
  422.   gtk_grab_add (widget);
  423.   gdk_pointer_grab (widget->window, TRUE,
  424.                     GDK_BUTTON_RELEASE_MASK |
  425.                     GDK_BUTTON_MOTION_MASK |
  426.                     GDK_POINTER_MOTION_HINT_MASK,
  427.                     NULL, NULL, 0);
  428.   gdk_window_raise (widget->window);
  429. }
  430.  
  431.  
  432. #ifdef RAPH_IS_HOME
  433. static void
  434. maybeblocked_expose (GtkWidget      *widget, 
  435.              GdkEventExpose *event)
  436. {
  437.   if (playing)
  438.     gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "expose_event");
  439.   else
  440.     repaint_sda (widget, event);
  441. }
  442. #else
  443.  
  444.  
  445. static void
  446. blocked_expose (GtkWidget      *widget, 
  447.         GdkEventExpose *event)
  448. {
  449.   gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "expose_event");
  450. }
  451. #endif
  452.  
  453.  
  454. #ifdef I_AM_STUPID
  455. static void
  456. xblocked_expose (GtkWidget      *widget, 
  457.          GdkEventExpose *event)
  458. {
  459.   printf("eep!\n");fflush(stdout);
  460.   abort();
  461. }
  462.  
  463. static void
  464. unblocked_expose (GtkWidget      *widget, 
  465.           GdkEventExpose *event)
  466. {
  467.   gboolean should_block;
  468.   
  469.   printf("%p: t%d w:%p s:%d c:%d \n",widget, event->type, event->window,
  470.      event->send_event, event->count);
  471.   fflush(stdout);
  472.  
  473.   return;
  474.   
  475.   /*
  476.    * If the animation is playing, we only respond to exposures
  477.    * which are artificially generated as a result of i.e.
  478.    * draw_widget.  This is to avoid needlessly redrawing twice
  479.    * per frame, because also 'real' exposure events may be generated
  480.    * by reshaping the windoow.
  481.    *
  482.    * If the animation is not playing, then we respond to any type
  483.    * of expose event.
  484.    */
  485.      
  486.   if (playing)
  487.     should_block = (!event->send_event) || (event->count != 0);
  488.   else
  489.     should_block = FALSE;
  490.  
  491.   if (should_block)
  492.     {
  493.       /*
  494.        * Since a whole load of exposures can come back-to-back,
  495.        * starvation can occur for the dialog etc.  This alleviates
  496.        * the pain.
  497.        */
  498.       while (gtk_events_pending())
  499.     gtk_main_iteration_do(TRUE);
  500.  
  501.       /*
  502.        * Block the expose from being acted upon.
  503.        */
  504.       blocked_expose(widget, event);
  505.  
  506.       return;
  507.     }
  508. }
  509. #endif
  510.  
  511.  
  512. static void
  513. shape_released (GtkWidget *widget)
  514. {
  515.   gtk_grab_remove (widget);
  516.   gdk_pointer_ungrab (0);
  517.   gdk_flush();
  518. }
  519.  
  520.  
  521. static void
  522. shape_motion (GtkWidget      *widget,
  523.               GdkEventMotion *event)
  524. {
  525.   gint xp, yp;
  526.   CursorOffset * p;
  527.   GdkModifierType mask;
  528.  
  529.   gdk_window_get_pointer (root_win, &xp, &yp, &mask);
  530.  
  531.   /*  printf("%u %d\n", mask, event->state);fflush(stdout); */
  532.  
  533.   /* if a button is still held by the time we process this event... */
  534.   if (mask & (GDK_BUTTON1_MASK|
  535.           GDK_BUTTON2_MASK|
  536.           GDK_BUTTON3_MASK|
  537.           GDK_BUTTON4_MASK|
  538.           GDK_BUTTON5_MASK))
  539.     {
  540.       p = gtk_object_get_user_data (GTK_OBJECT (widget));
  541.  
  542.       gtk_widget_set_uposition (widget, xp  - p->x, yp  - p->y);
  543.     }
  544.   else /* the user has released all buttons */
  545.     {
  546.       shape_released(widget);
  547.     }
  548. }
  549.  
  550.  
  551. #ifdef RAPH_IS_HOME
  552. static void
  553. repaint_da (GtkWidget *darea, 
  554.         gpointer   data)
  555. {
  556.   /*  printf("Repaint!  Woohoo!\n");*/
  557.   gdk_draw_rgb_image (drawing_area->window,
  558.               drawing_area->style->white_gc,
  559.               0, 0, width, height,
  560.               (total_frames==1)?GDK_RGB_DITHER_MAX:DITHERTYPE,
  561.               drawing_area_data, width * 3);
  562. }
  563.  
  564.  
  565. static void
  566. repaint_sda (GtkWidget *darea, 
  567.          gpointer   data)
  568. {
  569.   /*printf("Repaint!  Woohoo!\n");*/
  570.   gdk_draw_rgb_image (shape_drawing_area->window,
  571.               shape_drawing_area->style->white_gc,
  572.               0, 0, width, height,
  573.               (total_frames==1)?GDK_RGB_DITHER_MAX:DITHERTYPE,
  574.               shape_drawing_area_data, width * 3);
  575. }
  576. #endif
  577.  
  578.  
  579. static void
  580. preview_pressed (GtkWidget      *widget, 
  581.          GdkEventButton *event)
  582. {
  583. #ifdef RAPH_IS_HOME
  584. #else
  585.   gint i;
  586. #endif
  587.   gint xp, yp;
  588.   GdkModifierType mask;
  589.  
  590.   if (shaping) return;
  591.   
  592. #ifdef RAPH_IS_HOME
  593.   /* Create a total-alpha buffer merely for the not-shaped
  594.      drawing area to now display. */
  595.  
  596.   drawing_area_data = g_malloc (width * height * 3);
  597.   total_alpha_preview (drawing_area_data);
  598.  
  599. #else
  600.   /* put current preview buf into shaped buf */
  601.   for (i=0;i<height;i++)
  602.     {
  603.       gtk_preview_draw_row (shape_preview,
  604.                 &preview_data[3*i*width],
  605.                 0, i, width);
  606.   }
  607.   total_alpha_preview (preview_data);
  608. #endif
  609.       
  610.   gdk_window_get_pointer (root_win, &xp, &yp, &mask);
  611.   gtk_widget_set_uposition (shape_window, xp  - event->x, yp  - event->y);
  612.   
  613.   gtk_widget_show (shape_window);
  614.  
  615.   gdk_window_set_back_pixmap(shape_window->window, NULL, 0);
  616. #ifdef RAPH_IS_HOME
  617.   gdk_window_set_back_pixmap(shape_drawing_area->window, NULL, 1);
  618. #else
  619.   gdk_window_set_back_pixmap(shape_fixed->window, NULL, 1);
  620. #endif
  621.  
  622. #ifdef RAPH_IS_HOME
  623. #else
  624.   for (i=0;i<height;i++)
  625.     {
  626.       gtk_preview_draw_row (preview,
  627.                 &preview_data[3*i*width],
  628.                 0, i, width);
  629.     }
  630. #endif
  631.   show_frame();
  632.  
  633.   shaping = 1;
  634.   memset(shape_preview_mask, 0, (width*height)/8 + height);
  635.   render_frame(frame_number);
  636.   show_frame();
  637.   
  638. #ifdef RAPH_IS_HOME
  639.   repaint_da (NULL,NULL);
  640. #endif
  641.  
  642.   /* mildly amusing hack */
  643.   shape_pressed(shape_window, event);
  644. }
  645.  
  646.  
  647.  
  648. static void
  649. build_dialog (GimpImageBaseType  basetype,
  650.           char       *imagename)
  651. {
  652.   gchar* windowname;
  653.   CursorOffset* icon_pos;
  654.   GtkAdjustment *adj;
  655.  
  656.   GtkWidget* dlg;
  657.   GtkWidget* button;
  658.   GtkWidget* frame;
  659.   GtkWidget* frame2;
  660.   GtkWidget* vbox;
  661.   GtkWidget* hbox;
  662.   GtkWidget* hbox2;
  663.   GtkWidget* eventbox;
  664.   GdkCursor* cursor;
  665.  
  666.   gimp_ui_init ("animationplay", TRUE);
  667.  
  668.   windowname = g_strconcat (_("Animation Playback: "), imagename, NULL);
  669.  
  670.   dlg = gimp_dialog_new (windowname, "animationplay",
  671.              gimp_standard_help_func, "filters/animationplay.html",
  672.              GTK_WIN_POS_MOUSE,
  673.              FALSE, TRUE, FALSE,
  674.  
  675.              _("Close"), window_close_callback,
  676.              NULL, 1, NULL, TRUE, TRUE,
  677.  
  678.              NULL);
  679.  
  680.   g_free (windowname);
  681.  
  682.   gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
  683.               GTK_SIGNAL_FUNC (window_delete_callback),
  684.               NULL);
  685.  
  686.   {
  687.     /* The 'playback' half of the dialog */
  688.     
  689.     windowname = g_malloc (strlen (_("Playback: ")) + strlen (imagename) + 1);
  690.     if (total_frames > 1)
  691.       {
  692.     strcpy (windowname, _("Playback: "));
  693.     strcat (windowname, imagename);
  694.       }
  695.     else
  696.       {
  697.     strcpy (windowname, imagename);    
  698.       }
  699.     frame = gtk_frame_new (windowname);
  700.     g_free (windowname);
  701.     gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  702.     gtk_container_set_border_width (GTK_CONTAINER (frame), 3);
  703.     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
  704.             frame, TRUE, TRUE, 0);
  705.     
  706.     {
  707.       hbox = gtk_hbox_new (FALSE, 5);
  708.       gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
  709.       gtk_container_add (GTK_CONTAINER (frame), hbox);
  710.       
  711.       {
  712.     vbox = gtk_vbox_new (FALSE, 5);
  713.     gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
  714.     gtk_container_add (GTK_CONTAINER (hbox), vbox);
  715.     
  716.     {
  717.       hbox2 = gtk_hbox_new (FALSE, 0);
  718.       gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0);
  719.       gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0);
  720.       
  721.       {
  722.         psbutton = gtk_toggle_button_new_with_label ( _("Play/Stop"));
  723.         gtk_signal_connect (GTK_OBJECT (psbutton), "toggled",
  724.                 (GtkSignalFunc) playstop_callback, NULL);
  725.         gtk_box_pack_start (GTK_BOX (hbox2), psbutton, TRUE, TRUE, 0);
  726.         gtk_widget_show (psbutton);
  727.         
  728.         button = gtk_button_new_with_label ( _("Rewind"));
  729.         gtk_signal_connect (GTK_OBJECT (button), "clicked",
  730.                 (GtkSignalFunc) rewind_callback, NULL);
  731.         gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
  732.         gtk_widget_show (button);
  733.         
  734.         button = gtk_button_new_with_label ( _("Step"));
  735.         gtk_signal_connect (GTK_OBJECT (button), "clicked",
  736.                 (GtkSignalFunc) step_callback, NULL);
  737.         gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
  738.         gtk_widget_show (button);
  739.       }
  740.       /* If there aren't multiple frames, playback controls make no
  741.          sense */
  742.       /*      if (total_frames<=1) gtk_widget_set_sensitive (hbox2, FALSE);
  743.       gtk_widget_show(hbox2);*/
  744.  
  745.       if (total_frames>1)
  746.         gtk_widget_show(hbox2);
  747.  
  748.       hbox2 = gtk_hbox_new (TRUE, 0);
  749.       gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0);
  750.       gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
  751.       {
  752.         frame2 = gtk_frame_new (NULL);
  753.         gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_IN);
  754.         gtk_box_pack_start (GTK_BOX (hbox2), frame2, FALSE, FALSE, 0);
  755.         
  756.         {
  757.           eventbox = gtk_event_box_new();
  758.           gtk_container_add (GTK_CONTAINER (frame2), GTK_WIDGET (eventbox));
  759.           
  760.           {
  761. #ifdef RAPH_IS_HOME
  762.         drawing_area = gtk_drawing_area_new ();
  763.                 gtk_widget_set_usize (drawing_area, width, height);
  764.                 gtk_container_add (GTK_CONTAINER (eventbox),
  765.                                    GTK_WIDGET (drawing_area));
  766.                 gtk_widget_show (drawing_area);
  767. #else
  768.         preview =
  769.           GTK_PREVIEW (gtk_preview_new (GTK_PREVIEW_COLOR));/* FIXME */
  770.         gtk_preview_size (preview, width, height);
  771.         gtk_container_add (GTK_CONTAINER (eventbox),
  772.                    GTK_WIDGET (preview));
  773.         gtk_widget_show(GTK_WIDGET (preview));
  774. #endif
  775.           }
  776.           gtk_widget_show(eventbox);
  777.           gtk_widget_set_events (eventbox,
  778.                      gtk_widget_get_events (eventbox)
  779.                      | GDK_BUTTON_PRESS_MASK);
  780.         }
  781.         gtk_widget_show(frame2);
  782.       }
  783.       gtk_widget_show(hbox2);
  784.  
  785.  
  786.       adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, total_frames,
  787.                               1, 1, 1);
  788.       progress = GTK_PROGRESS_BAR (gtk_progress_bar_new_with_adjustment
  789.                        (adj));
  790.       {
  791.         gtk_progress_set_format_string (GTK_PROGRESS (progress),
  792.                         _("Frame %v of %u"));
  793.         gtk_progress_set_show_text (GTK_PROGRESS (progress), TRUE);
  794.         /*      gtk_widget_set_usize (GTK_WIDGET (progress), 150, 15);*/
  795.         gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (progress),
  796.                 TRUE, TRUE, 0);
  797.       }
  798.       if (total_frames>1)
  799.         gtk_widget_show (GTK_WIDGET (progress));
  800.     }
  801.     gtk_widget_show(vbox);
  802.     
  803.       }
  804.       gtk_widget_show(hbox);
  805.       
  806.     }
  807.     gtk_widget_show(frame);
  808.     
  809.   }
  810.   gtk_widget_show(dlg);
  811.  
  812.  
  813.   /* let's get into shape. */
  814.   shape_window = gtk_window_new (GTK_WINDOW_POPUP);
  815.   {
  816. #ifdef RAPH_IS_HOME
  817.     shape_drawing_area = gtk_drawing_area_new ();
  818.     {
  819.       gtk_widget_set_usize (shape_drawing_area, width, height);
  820.       gtk_container_add (GTK_CONTAINER (shape_window), shape_drawing_area);
  821.     }
  822.     gtk_widget_show (shape_drawing_area);
  823.     gtk_widget_set_events (shape_drawing_area,
  824.                gtk_widget_get_events (shape_drawing_area)
  825.                | GDK_BUTTON_PRESS_MASK);
  826. #else
  827.     shape_fixed = gtk_fixed_new ();
  828.     {
  829.       gtk_widget_set_usize (shape_fixed, width,height);
  830.       gtk_container_add (GTK_CONTAINER (shape_window), shape_fixed);
  831.  
  832.       shape_preview =
  833.     GTK_PREVIEW (gtk_preview_new (GTK_PREVIEW_COLOR)); /* FIXME */
  834.       {
  835.     gtk_preview_size (shape_preview, width, height);
  836.       }
  837.     }
  838.     gtk_widget_show (shape_fixed);
  839. #endif
  840.     gtk_widget_realize (shape_window);
  841.  
  842. #ifdef RAPH_IS_HOME
  843. #else
  844.     shape_pixmap = gdk_pixmap_new (shape_window->window,
  845.                    width, height,
  846.                    gtk_preview_get_visual()->depth);
  847. #endif
  848.     
  849.     gdk_window_set_back_pixmap(shape_window->window, NULL, 0);
  850.  
  851.     cursor = gdk_cursor_new (GDK_CENTER_PTR);
  852.     gdk_window_set_cursor(shape_window->window, cursor);
  853.     gdk_cursor_destroy (cursor);
  854.  
  855.     gtk_signal_connect (GTK_OBJECT (shape_window), "button_press_event",
  856.             GTK_SIGNAL_FUNC (shape_pressed),NULL);
  857.     gtk_signal_connect (GTK_OBJECT (shape_window), "button_release_event",
  858.             GTK_SIGNAL_FUNC (shape_released),NULL);
  859.     gtk_signal_connect (GTK_OBJECT (shape_window), "motion_notify_event",
  860.             GTK_SIGNAL_FUNC (shape_motion),NULL);
  861.  
  862.     icon_pos = g_new (CursorOffset, 1);
  863.     gtk_object_set_user_data(GTK_OBJECT(shape_window), icon_pos);
  864.   }
  865.   /*  gtk_widget_show (shape_window);*/
  866.  
  867.   gtk_signal_connect (GTK_OBJECT (eventbox), "button_press_event",
  868.               GTK_SIGNAL_FUNC (preview_pressed),NULL);
  869.  
  870. #ifdef I_AM_STUPID
  871.   gtk_signal_connect (GTK_OBJECT (shape_window), "expose_event",
  872.               GTK_SIGNAL_FUNC (unblocked_expose),shape_window);
  873. #endif
  874.  
  875. #ifdef RAPH_IS_HOME
  876.   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
  877.               GTK_SIGNAL_FUNC (repaint_da), drawing_area);
  878.  
  879.   gtk_signal_connect (GTK_OBJECT (shape_drawing_area), "expose_event",
  880.               GTK_SIGNAL_FUNC (maybeblocked_expose),
  881.               shape_drawing_area);
  882. #else
  883.   gtk_signal_connect (GTK_OBJECT (shape_fixed), "expose_event",
  884.               GTK_SIGNAL_FUNC (blocked_expose),shape_fixed);
  885. #endif
  886.  
  887.   root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ());
  888. }
  889.  
  890.  
  891.  
  892. static void 
  893. do_playback (void)
  894. {
  895.   int i;
  896.  
  897.   width     = gimp_image_width(image_id);
  898.   height    = gimp_image_height(image_id);
  899.   layers    = gimp_image_get_layers (image_id, &total_frames);
  900.   imagetype = gimp_image_base_type(image_id);
  901.  
  902.   if (imagetype == GIMP_INDEXED)
  903.     palette = gimp_image_get_cmap(image_id, &ncolours);
  904.   else if (imagetype == GIMP_GRAY)
  905.     {
  906.       /* This is a bit sick, until this plugin ever gets
  907.      real GRAY support (not worth it?) */
  908.       palette = g_malloc(768);
  909.       for (i=0;i<256;i++)
  910.       {
  911.           palette[i*3] = palette[i*3+1] = palette[i*3+2] = i;
  912.       }
  913.       ncolours = 256;
  914.     }
  915.  
  916.  
  917.   frame_number = 0;
  918.   
  919.   /* cache hint "cache nothing", since we iterate over every
  920.      tile in every layer. */
  921.   gimp_tile_cache_size (0);
  922.  
  923.   init_preview_misc();
  924.  
  925.   build_dialog(gimp_image_base_type(image_id),
  926.                gimp_image_get_filename(image_id));
  927.  
  928.   /* Make sure that whole preview is dirtied with pure-alpha */
  929.   total_alpha_preview(preview_data);
  930.  
  931. #ifdef RAPH_IS_HOME
  932.   /*  gdk_draw_rgb_image (drawing_area->window,
  933.               drawing_area->style->white_gc,
  934.               0, 0, width, height,
  935.               DITHERTYPE,
  936.               preview_data, width * 3);*/
  937. #else
  938.   for (i=0;i<height;i++)
  939.   {
  940.     gtk_preview_draw_row (preview,
  941.                           &preview_data[3*i*width],
  942.                           0, i, width);
  943.   }
  944. #endif
  945.   
  946.   render_frame(0);
  947.   show_frame();
  948.  
  949.   gtk_main ();
  950.   gdk_flush ();
  951. }
  952.  
  953.  
  954. /* Rendering Functions */
  955.  
  956. static void
  957. render_frame (gint32 whichframe)
  958. {
  959.   GimpPixelRgn pixel_rgn;
  960.   static guchar *rawframe = NULL;
  961.   static gint rawwidth=0, rawheight=0, rawbpp=0;
  962.   gint rawx=0, rawy=0;
  963.   guchar* srcptr;
  964.   guchar* destptr;
  965.   gint i,j,k; /* imaginative loop variables */
  966.   DisposeType dispose;
  967.  
  968.  
  969.   if (whichframe >= total_frames)
  970.     {
  971.       printf( "playback: Asked for frame number %d in a %d-frame animation!\n",
  972.          (int) (whichframe+1), (int) total_frames);
  973.       exit(-1);
  974.     }
  975.  
  976.   drawable = gimp_drawable_get (layers[total_frames-(whichframe+1)]);
  977.   /* Lame attempt to catch the case that a user has closed the image. */
  978.   if (! (drawable->width > 0 && drawable->height > 0))
  979.     {
  980.       gtk_main_quit ();
  981.       return;
  982.     }
  983.  
  984.   dispose = get_frame_disposal(frame_number);
  985.  
  986.   /* Image has been closed/etc since we got the layer list? */
  987.   /* FIXME - How do we tell if a gimp_drawable_get() fails? */
  988.   if (gimp_drawable_width(drawable->id)==0)
  989.     window_close_callback (NULL, NULL);
  990.  
  991.   if (((dispose==DISPOSE_REPLACE)||(whichframe==0)) &&
  992.       gimp_drawable_has_alpha(drawable->id))
  993.     {
  994.       total_alpha_preview(preview_data);
  995.     }
  996.  
  997.  
  998.   /* only get a new 'raw' drawable-data buffer if this and
  999.      the previous raw buffer were different sizes*/
  1000.  
  1001.   if ((rawwidth*rawheight*rawbpp)
  1002.       !=
  1003.       ((gimp_drawable_width(drawable->id)*
  1004.     gimp_drawable_height(drawable->id)*
  1005.     gimp_drawable_bpp(drawable->id))))
  1006.     {
  1007.       if (rawframe != NULL) g_free(rawframe);
  1008.       rawframe = g_malloc((gimp_drawable_width(drawable->id)) *
  1009.               (gimp_drawable_height(drawable->id)) *
  1010.               (gimp_drawable_bpp(drawable->id)));
  1011.     }
  1012.     
  1013.   rawwidth = gimp_drawable_width(drawable->id);
  1014.   rawheight = gimp_drawable_height(drawable->id);
  1015.   rawbpp = gimp_drawable_bpp(drawable->id);
  1016.  
  1017.  
  1018.   /* Initialise and fetch the whole raw new frame */
  1019.  
  1020.   gimp_pixel_rgn_init (&pixel_rgn,
  1021.                drawable,
  1022.                0, 0,
  1023.                drawable->width, drawable->height,
  1024.                FALSE,
  1025.                FALSE);
  1026.   gimp_pixel_rgn_get_rect (&pixel_rgn,
  1027.                rawframe,
  1028.                0, 0,
  1029.                drawable->width, drawable->height);
  1030.   /*  gimp_pixel_rgns_register (1, &pixel_rgn);*/
  1031.  
  1032.   gimp_drawable_offsets (drawable->id,
  1033.              &rawx,
  1034.              &rawy);
  1035.  
  1036.  
  1037.   /* render... */
  1038.  
  1039.   switch (imagetype)
  1040.     {
  1041.     case GIMP_RGB:
  1042.       if ((rawwidth==width) &&
  1043.       (rawheight==height) &&
  1044.       (rawx==0) &&
  1045.       (rawy==0))
  1046.     {
  1047.       /* --- These cases are for the best cases,  in        --- */
  1048.       /* --- which this frame is the same size and position --- */
  1049.       /* --- as the preview buffer itself                   --- */
  1050.       
  1051.       if (gimp_drawable_has_alpha (drawable->id))
  1052.         { /* alpha */
  1053.           destptr = preview_data;
  1054.           srcptr  = rawframe;
  1055.           
  1056.           i = rawwidth*rawheight;
  1057.           while (i--)
  1058.         {
  1059.           if (!(*(srcptr+3)&128))
  1060.             {
  1061.               srcptr  += 4;
  1062.               destptr += 3;
  1063.               continue;
  1064.             }
  1065.           *(destptr++) = *(srcptr++);
  1066.           *(destptr++) = *(srcptr++);
  1067.           *(destptr++) = *(srcptr++);
  1068.           srcptr++;
  1069.         }
  1070.  
  1071.           /* calculate the shape mask */
  1072.           if (shaping)
  1073.         {
  1074.           srcptr = rawframe + 3;
  1075.           for (j=0;j<rawheight;j++)
  1076.             {
  1077.               k = j * ((7 + rawwidth) / 8);
  1078.               for (i=0;i<rawwidth;i++)
  1079.             {
  1080.               if ((*srcptr)&128)
  1081.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1082.  
  1083.               srcptr += 4;
  1084.             }
  1085.             }
  1086.         }
  1087.         }
  1088.       else /* no alpha */
  1089.         {
  1090.           if ((rawwidth==width)&&(rawheight==height))
  1091.         {
  1092.           /*printf("quickie\n");fflush(stdout);*/
  1093.           memcpy(preview_data, rawframe, width*height*3);
  1094.         }
  1095.  
  1096.           if (shaping)
  1097.         {
  1098.           /* opacify the shape mask */
  1099.           memset(shape_preview_mask, 255,
  1100.              (rawwidth*rawheight)/8 + rawheight);
  1101.         }
  1102.         }
  1103.       /* Display the preview buffer... finally. */
  1104.       if (shaping)
  1105.         {
  1106. #ifdef RAPH_IS_HOME
  1107.           reshape_from_bitmap (shape_preview_mask);
  1108.           gdk_draw_rgb_image (shape_drawing_area->window,
  1109.                   shape_drawing_area->style->white_gc,
  1110.                   0, 0, width, height,
  1111.                   (total_frames==1)?GDK_RGB_DITHER_MAX
  1112.                   :DITHERTYPE,
  1113.                   preview_data, width * 3);
  1114. #else
  1115.           for (i=0;i<height;i++)
  1116.         {
  1117.           gtk_preview_draw_row (shape_preview,
  1118.                     &preview_data[3*i*width],
  1119.                     0, i, width);
  1120.         }
  1121. #endif
  1122.         }
  1123.       else
  1124.         {
  1125. #ifdef RAPH_IS_HOME
  1126.           reshape_from_bitmap (shape_preview_mask);
  1127.           gdk_draw_rgb_image (drawing_area->window,
  1128.                   drawing_area->style->white_gc,
  1129.                   0, 0, width, height,
  1130.                   (total_frames==1)?GDK_RGB_DITHER_MAX
  1131.                   :DITHERTYPE,
  1132.                   preview_data, width * 3);
  1133. #else
  1134.           for (i=0;i<height;i++)
  1135.         {
  1136.           gtk_preview_draw_row (preview,
  1137.                     &preview_data[3*i*width],
  1138.                     0, i, width);
  1139.         }
  1140. #endif
  1141.         }
  1142.     }
  1143.       else
  1144.     {
  1145.       /* --- These are suboptimal catch-all cases for when  --- */
  1146.       /* --- this frame is bigger/smaller than the preview  --- */
  1147.       /* --- buffer, and/or offset within it.               --- */
  1148.       
  1149.       if (gimp_drawable_has_alpha (drawable->id))
  1150.         { /* alpha */
  1151.           
  1152.           srcptr = rawframe;
  1153.           
  1154.           for (j=rawy; j<rawheight+rawy; j++)
  1155.         {
  1156.           for (i=rawx; i<rawwidth+rawx; i++)
  1157.             {
  1158.               if ((i>=0 && i<width) &&
  1159.               (j>=0 && j<height))
  1160.             {
  1161.               if (*(srcptr+3)&128)
  1162.                 {
  1163.                   preview_data[(j*width+i)*3   ] = *(srcptr);
  1164.                   preview_data[(j*width+i)*3 +1] = *(srcptr+1);
  1165.                   preview_data[(j*width+i)*3 +2] = *(srcptr+2);
  1166.                 }
  1167.             }
  1168.               
  1169.               srcptr += 4;
  1170.             }
  1171.         }
  1172.           
  1173.           if (shaping)
  1174.         {
  1175.           srcptr = rawframe + 3;
  1176.           for (j=rawy; j<rawheight+rawy; j++)
  1177.             {
  1178.               k = j * ((width+7)/8);
  1179.               for (i=rawx; i<rawwidth+rawx; i++)
  1180.             {
  1181.               if ((i>=0 && i<width) &&
  1182.                   (j>=0 && j<height))
  1183.                 {
  1184.                   if ((*srcptr)&128)
  1185.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1186.                 }
  1187.               srcptr += 4;
  1188.             }
  1189.             }
  1190.         }
  1191.         }
  1192.       else
  1193.         {
  1194.           /* noalpha */
  1195.           
  1196.           srcptr = rawframe;
  1197.           
  1198.           for (j=rawy; j<rawheight+rawy; j++)
  1199.         {
  1200.           for (i=rawx; i<rawwidth+rawx; i++)
  1201.             {
  1202.               if ((i>=0 && i<width) &&
  1203.               (j>=0 && j<height))
  1204.             {
  1205.               preview_data[(j*width+i)*3   ] = *(srcptr);
  1206.               preview_data[(j*width+i)*3 +1] = *(srcptr+1);
  1207.               preview_data[(j*width+i)*3 +2] = *(srcptr+2);
  1208.             }
  1209.               
  1210.               srcptr += 3;
  1211.             }
  1212.         }
  1213.         }
  1214.       
  1215.       /* Display the preview buffer... finally. */
  1216.       if (shaping)
  1217.         {
  1218.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1219.         {
  1220. #ifdef RAPH_IS_HOME
  1221.           int top, bottom;
  1222.  
  1223.           top = (rawy < 0) ? 0 : rawy;
  1224.           bottom = (rawy+rawheight) < height ?
  1225.             (rawy+rawheight) : height-1;
  1226.  
  1227.           reshape_from_bitmap (shape_preview_mask);
  1228.           gdk_draw_rgb_image (shape_drawing_area->window,
  1229.                       shape_drawing_area->style->white_gc,
  1230.                       0, top, width, bottom-top,
  1231.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1232.                       :DITHERTYPE,
  1233.                       &preview_data[3*top*width], width * 3);
  1234. #else
  1235.           for (i=rawy;i<rawy+rawheight;i++)
  1236.             {
  1237.               if (i>=0 && i<height)
  1238.             gtk_preview_draw_row (shape_preview,
  1239.                           &preview_data[3*i*width],
  1240.                           0, i, width);
  1241.             }
  1242. #endif
  1243.         }
  1244.           else
  1245.         {
  1246. #ifdef RAPH_IS_HOME
  1247.           reshape_from_bitmap (shape_preview_mask);
  1248.           gdk_draw_rgb_image (shape_drawing_area->window,
  1249.                       shape_drawing_area->style->white_gc,
  1250.                       0, 0, width, height,
  1251.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1252.                       :DITHERTYPE,
  1253.                       preview_data, width * 3);
  1254. #else
  1255.           for (i=0;i<height;i++)
  1256.             {
  1257.               gtk_preview_draw_row (shape_preview,
  1258.                         &preview_data[3*i*width],
  1259.                         0, i, width);
  1260.             }
  1261. #endif
  1262.         }
  1263.         }
  1264.       else
  1265.         {
  1266.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1267.         {
  1268. #ifdef RAPH_IS_HOME
  1269.           int top, bottom;
  1270.  
  1271.           top = (rawy < 0) ? 0 : rawy;
  1272.           bottom = (rawy+rawheight) < height ?
  1273.             (rawy+rawheight) : height-1;
  1274.  
  1275.           gdk_draw_rgb_image (drawing_area->window,
  1276.                       drawing_area->style->white_gc,
  1277.                       0, top, width, bottom-top,
  1278.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1279.                       :DITHERTYPE,
  1280.                       &preview_data[3*top*width], width * 3);
  1281. #else
  1282.           for (i=rawy;i<rawy+rawheight;i++)
  1283.             {
  1284.               if (i>=0 && i<height)
  1285.             gtk_preview_draw_row (preview,
  1286.                           &preview_data[3*i*width],
  1287.                           0, i, width);
  1288.             }
  1289. #endif
  1290.         }
  1291.           else
  1292.         {
  1293. #ifdef RAPH_IS_HOME
  1294.           gdk_draw_rgb_image (drawing_area->window,
  1295.                       drawing_area->style->white_gc,
  1296.                       0, 0, width, height,
  1297.                       (total_frames==1)?GDK_RGB_DITHER_MAX:
  1298.                       DITHERTYPE,
  1299.                       preview_data, width * 3);
  1300. #else
  1301.           for (i=0;i<height;i++)
  1302.             {
  1303.               gtk_preview_draw_row (preview,
  1304.                         &preview_data[3*i*width],
  1305.                         0, i, width);
  1306.             }
  1307. #endif
  1308.         }
  1309.         }
  1310.     }
  1311.       break;
  1312.  
  1313.     case GIMP_GRAY:
  1314.     case GIMP_INDEXED:
  1315.       if ((rawwidth==width) &&
  1316.       (rawheight==height) &&
  1317.       (rawx==0) &&
  1318.       (rawy==0))
  1319.     {
  1320.       /* --- These cases are for the best cases,  in        --- */
  1321.       /* --- which this frame is the same size and position --- */
  1322.       /* --- as the preview buffer itself                   --- */
  1323.       
  1324.       if (gimp_drawable_has_alpha (drawable->id))
  1325.         { /* alpha */
  1326.           destptr = preview_data;
  1327.           srcptr  = rawframe;
  1328.           
  1329.           i = rawwidth*rawheight;
  1330.           while (i--)
  1331.         {
  1332.           if (!(*(srcptr+1)))
  1333.             {
  1334.               srcptr  += 2;
  1335.               destptr += 3;
  1336.               continue;
  1337.             }
  1338.           
  1339.           *(destptr++) = palette[3*(*(srcptr))];
  1340.           *(destptr++) = palette[1+3*(*(srcptr))];
  1341.           *(destptr++) = palette[2+3*(*(srcptr))];
  1342.           srcptr+=2;
  1343.         }
  1344.  
  1345.           /* calculate the shape mask */
  1346.           if (shaping)
  1347.         {
  1348.           srcptr = rawframe + 1;
  1349.           for (j=0;j<rawheight;j++)
  1350.             {
  1351.               k = j * ((7 + rawwidth) / 8);
  1352.               for (i=0;i<rawwidth;i++)
  1353.             {
  1354.               if (*srcptr)
  1355.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1356.               srcptr += 2;
  1357.             }
  1358.             }
  1359.         }
  1360.         }
  1361.       else /* no alpha */
  1362.         {
  1363.           destptr = preview_data;
  1364.           srcptr  = rawframe;
  1365.           
  1366.           i = rawwidth*rawheight;
  1367.           while (--i)
  1368.         {
  1369.           *(destptr++) = palette[3*(*(srcptr))];
  1370.           *(destptr++) = palette[1+3*(*(srcptr))];
  1371.           *(destptr++) = palette[2+3*(*(srcptr))];
  1372.           srcptr++;
  1373.         }
  1374.  
  1375.           if (shaping)
  1376.         {
  1377.           /* opacify the shape mask */
  1378.           memset(shape_preview_mask, 255,
  1379.              (rawwidth*rawheight)/8 + rawheight);
  1380.         }
  1381.         }
  1382.       
  1383.       /* Display the preview buffer... finally. */
  1384.       if (shaping)
  1385.         {
  1386. #ifdef RAPH_IS_HOME
  1387.           reshape_from_bitmap (shape_preview_mask);
  1388.           gdk_draw_rgb_image (shape_drawing_area->window,
  1389.                   shape_drawing_area->style->white_gc,
  1390.                   0, 0, width, height,
  1391.                   (total_frames==1)?GDK_RGB_DITHER_MAX:
  1392.                   DITHERTYPE,
  1393.                   preview_data, width * 3);
  1394. #else
  1395.           for (i=0;i<height;i++)
  1396.         {
  1397.           gtk_preview_draw_row (shape_preview,
  1398.                     &preview_data[3*i*width],
  1399.                     0, i, width);
  1400.         }
  1401. #endif
  1402.         }
  1403.       else
  1404.         {
  1405. #ifdef RAPH_IS_HOME
  1406.           gdk_draw_rgb_image (drawing_area->window,
  1407.                   drawing_area->style->white_gc,
  1408.                   0, 0, width, height,
  1409.                   (total_frames==1)?GDK_RGB_DITHER_MAX:
  1410.                   DITHERTYPE,
  1411.                   preview_data, width * 3);
  1412. #else
  1413.           for (i=0;i<height;i++)
  1414.         {
  1415.           gtk_preview_draw_row (preview,
  1416.                     &preview_data[3*i*width],
  1417.                     0, i, width);
  1418.         }
  1419. #endif
  1420.         }
  1421.     }
  1422.       else
  1423.     {
  1424.       /* --- These are suboptimal catch-all cases for when  --- */
  1425.       /* --- this frame is bigger/smaller than the preview  --- */
  1426.       /* --- buffer, and/or offset within it.               --- */
  1427.       
  1428.       if (gimp_drawable_has_alpha (drawable->id))
  1429.         { /* alpha */
  1430.           
  1431.           srcptr = rawframe;
  1432.           
  1433.           for (j=rawy; j<rawheight+rawy; j++)
  1434.         {
  1435.           for (i=rawx; i<rawwidth+rawx; i++)
  1436.             {
  1437.               if ((i>=0 && i<width) &&
  1438.               (j>=0 && j<height))
  1439.             {
  1440.               if (*(srcptr+1))
  1441.                 {
  1442.                   preview_data[(j*width+i)*3   ] =
  1443.                 palette[3*(*(srcptr))];
  1444.                   preview_data[(j*width+i)*3 +1] =
  1445.                 palette[1+3*(*(srcptr))];
  1446.                   preview_data[(j*width+i)*3 +2] =
  1447.                 palette[2+3*(*(srcptr))];
  1448.                 }
  1449.             }
  1450.               
  1451.               srcptr += 2;
  1452.             }
  1453.         }
  1454.           
  1455.           if (shaping)
  1456.         {
  1457.           srcptr = rawframe + 1;
  1458.           for (j=rawy; j<rawheight+rawy; j++)
  1459.             {
  1460.               k = j * ((width+7)/8);
  1461.               for (i=rawx; i<rawwidth+rawx; i++)
  1462.             {
  1463.               if ((i>=0 && i<width) &&
  1464.                   (j>=0 && j<height))
  1465.                 {
  1466.                   if (*srcptr)
  1467.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1468.                 }
  1469.               srcptr += 2;
  1470.             }
  1471.             }
  1472.         }
  1473.         }
  1474.       else
  1475.         {
  1476.           /* noalpha */
  1477.  
  1478.           srcptr = rawframe;
  1479.           
  1480.           for (j=rawy; j<rawheight+rawy; j++)
  1481.         {
  1482.           for (i=rawx; i<rawwidth+rawx; i++)
  1483.             {
  1484.               if ((i>=0 && i<width) &&
  1485.               (j>=0 && j<height))
  1486.             {
  1487.               preview_data[(j*width+i)*3   ] =
  1488.                 palette[3*(*(srcptr))];
  1489.               preview_data[(j*width+i)*3 +1] =
  1490.                 palette[1+3*(*(srcptr))];
  1491.               preview_data[(j*width+i)*3 +2] =
  1492.                 palette[2+3*(*(srcptr))];
  1493.             }
  1494.               
  1495.               srcptr ++;
  1496.             }
  1497.         }
  1498.         }
  1499.       
  1500.       /* Display the preview buffer... finally. */
  1501.       if (shaping)
  1502.         {
  1503.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1504.         {
  1505. #ifdef RAPH_IS_HOME
  1506.           int top, bottom;
  1507.  
  1508.           top = (rawy < 0) ? 0 : rawy;
  1509.           bottom = (rawy+rawheight) < height ?
  1510.             (rawy+rawheight) : height-1;
  1511.  
  1512.           reshape_from_bitmap (shape_preview_mask);
  1513.           gdk_draw_rgb_image (shape_drawing_area->window,
  1514.                       shape_drawing_area->style->white_gc,
  1515.                       0, top, width, bottom-top,
  1516.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1517.                       :DITHERTYPE,
  1518.                       &preview_data[3*top*width], width * 3);
  1519. #else
  1520.           for (i=rawy;i<rawy+rawheight;i++)
  1521.             {
  1522.               if (i>=0 && i<height)
  1523.             gtk_preview_draw_row (shape_preview,
  1524.                           &preview_data[3*i*width],
  1525.                           0, i, width);
  1526.             }
  1527. #endif
  1528.         }
  1529.           else
  1530.         {
  1531. #ifdef RAPH_IS_HOME
  1532.           reshape_from_bitmap (shape_preview_mask);
  1533.           gdk_draw_rgb_image (shape_drawing_area->window,
  1534.                       shape_drawing_area->style->white_gc,
  1535.                       0, 0, width, height,
  1536.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1537.                       :DITHERTYPE,
  1538.                       preview_data, width * 3);
  1539. #else
  1540.           for (i=0;i<height;i++)
  1541.             {
  1542.               gtk_preview_draw_row (shape_preview,
  1543.                         &preview_data[3*i*width],
  1544.                         0, i, width);
  1545.             }
  1546. #endif
  1547.         }
  1548.         }
  1549.       else
  1550.         {
  1551.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1552.         {
  1553. #ifdef RAPH_IS_HOME
  1554.           int top, bottom;
  1555.  
  1556.           top = (rawy < 0) ? 0 : rawy;
  1557.           bottom = (rawy+rawheight) < height ?
  1558.             (rawy+rawheight) : height-1;
  1559.  
  1560.           gdk_draw_rgb_image (drawing_area->window,
  1561.                       drawing_area->style->white_gc,
  1562.                       0, top, width, bottom-top,
  1563.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1564.                       :DITHERTYPE,
  1565.                       &preview_data[3*top*width], width * 3);
  1566. #else
  1567.           for (i=rawy;i<rawy+rawheight;i++)
  1568.             {
  1569.               if (i>=0 && i<height)
  1570.             gtk_preview_draw_row (preview,
  1571.                           &preview_data[3*i*width],
  1572.                           0, i, width);
  1573.             }
  1574. #endif
  1575.         }
  1576.           else
  1577.         {
  1578. #ifdef RAPH_IS_HOME
  1579.           gdk_draw_rgb_image (drawing_area->window,
  1580.                       drawing_area->style->white_gc,
  1581.                       0, 0, width, height,
  1582.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1583.                       :DITHERTYPE,
  1584.                       preview_data, width * 3);
  1585. #else
  1586.           for (i=0;i<height;i++)
  1587.             {
  1588.               gtk_preview_draw_row (preview,
  1589.                         &preview_data[3*i*width],
  1590.                         0, i, width);
  1591.             }
  1592. #endif
  1593.         }
  1594.         }
  1595.     }
  1596.       break;
  1597.       
  1598.     }
  1599.  
  1600.   /* clean up */  
  1601.   gimp_drawable_detach(drawable);
  1602. }
  1603.  
  1604.  
  1605. /* If we're using GDKRGB, we don't reshape in this function because
  1606.    it's too late (GDKRGB is synchronous).  So this just updates the
  1607.    progress bar. */
  1608. static void
  1609. show_frame (void)
  1610. {
  1611. #ifndef RAPH_IS_HOME
  1612.   GdkGC *gc;
  1613.  
  1614.   /* Tell GTK to physically draw the preview */
  1615.   if (!shaping)
  1616.     {
  1617.       gtk_widget_draw (GTK_WIDGET (preview), NULL);
  1618.     }
  1619.  
  1620.   if (shaping)
  1621.     {
  1622.       /* Try to avoid starvation of UI events */
  1623.       while (gtk_events_pending())
  1624.     gtk_main_iteration_do(TRUE);
  1625.  
  1626.       gc = gdk_gc_new (shape_pixmap);
  1627.       gtk_preview_put (GTK_PREVIEW (shape_preview),
  1628.                shape_pixmap, gc,
  1629.                0, 0, 0, 0, width, height);
  1630.       gdk_gc_destroy (gc);
  1631.       gdk_window_set_back_pixmap(shape_window->window, shape_pixmap,
  1632.                  FALSE);
  1633.  
  1634.       reshape_from_bitmap(shape_preview_mask);
  1635.  
  1636.       gdk_flush();
  1637.  
  1638.       gtk_widget_queue_draw(shape_window);
  1639.     }
  1640. #endif /* ! RAPH_IS_HOME */
  1641.  
  1642.   /* update the dialog's progress bar */
  1643.   gtk_progress_bar_update (progress,
  1644.                ((float)frame_number/(float)(total_frames-0.999)));
  1645. }
  1646.  
  1647.  
  1648. static void
  1649. init_preview_misc (void)
  1650. {
  1651.   int i;
  1652.  
  1653.   preview_data = g_malloc(width*height*3);
  1654.   shape_preview_mask = g_malloc((width*height)/8 + 1 + height);
  1655.   preview_alpha1_data = g_malloc(width*3);
  1656.   preview_alpha2_data = g_malloc(width*3);
  1657.  
  1658.   for (i=0;i<width;i++)
  1659.     {
  1660.       if (i&8)
  1661.     {
  1662.       preview_alpha1_data[i*3 +0] =
  1663.       preview_alpha1_data[i*3 +1] =
  1664.       preview_alpha1_data[i*3 +2] = 102;
  1665.       preview_alpha2_data[i*3 +0] =
  1666.       preview_alpha2_data[i*3 +1] =
  1667.       preview_alpha2_data[i*3 +2] = 154;
  1668.     }
  1669.       else
  1670.     {
  1671.       preview_alpha1_data[i*3 +0] =
  1672.       preview_alpha1_data[i*3 +1] =
  1673.       preview_alpha1_data[i*3 +2] = 154;
  1674.       preview_alpha2_data[i*3 +0] =
  1675.       preview_alpha2_data[i*3 +1] =
  1676.       preview_alpha2_data[i*3 +2] = 102;
  1677.     }
  1678.     }
  1679.  
  1680. #ifdef RAPH_IS_HOME
  1681.   drawing_area_data = preview_data;
  1682.   shape_drawing_area_data = preview_data;
  1683. #endif
  1684. }
  1685.  
  1686.  
  1687. static void
  1688. total_alpha_preview (guchar* ptr)
  1689. {
  1690.   int i;
  1691.  
  1692.   if (shaping)
  1693.     {
  1694.       memset(shape_preview_mask, 0, (width*height)/8 + height);
  1695.     }
  1696.   else
  1697.     {
  1698.       for (i=0;i<height;i++)
  1699.     {
  1700.       if (i&8)
  1701.         memcpy(&ptr[i*3*width], preview_alpha1_data, 3*width);
  1702.       else
  1703.         memcpy(&ptr[i*3*width], preview_alpha2_data, 3*width);
  1704.     }
  1705.     }
  1706. }
  1707.  
  1708.  
  1709.  
  1710. /* Util. */
  1711.  
  1712. static void
  1713. remove_timer (void)
  1714. {
  1715.   if (timer)
  1716.     {
  1717.       gtk_timeout_remove (timer);
  1718.       timer = 0;
  1719.     }
  1720. }
  1721.  
  1722. static void
  1723. do_step (void)
  1724. {
  1725.   frame_number = (frame_number+1)%total_frames;
  1726.   render_frame(frame_number);
  1727. }
  1728.  
  1729.  
  1730. /*  Callbacks  */
  1731.  
  1732. static gint
  1733. window_delete_callback (GtkWidget *widget,
  1734.                 GdkEvent  *event,
  1735.                 gpointer   data)
  1736. {
  1737.   if (playing)
  1738.     playstop_callback(NULL, NULL);
  1739.  
  1740.   if (shape_window)
  1741.     gtk_widget_destroy(GTK_WIDGET(shape_window));
  1742.  
  1743.   gdk_flush();
  1744.   gtk_main_quit();
  1745.  
  1746.   return FALSE;
  1747. }
  1748.  
  1749. static void
  1750. window_close_callback (GtkWidget *widget,
  1751.                gpointer   data)
  1752. {
  1753.   if (data)
  1754.     gtk_widget_destroy(GTK_WIDGET(data));
  1755.  
  1756.   window_delete_callback (NULL, NULL, NULL);
  1757. }
  1758.  
  1759. static gint
  1760. advance_frame_callback (GtkWidget *widget,
  1761.             gpointer   data)
  1762. {
  1763.   remove_timer();
  1764.  
  1765.   timer = gtk_timeout_add (get_frame_duration((frame_number+1)%total_frames),
  1766.                (GtkFunction) advance_frame_callback, NULL);
  1767.  
  1768.   do_step();
  1769.   show_frame();
  1770.  
  1771.   return FALSE;
  1772. }
  1773.  
  1774. static void
  1775. playstop_callback (GtkWidget *widget,
  1776.            gpointer   data)
  1777. {
  1778.   if (!playing)
  1779.     { /* START PLAYING */
  1780.       playing = TRUE;
  1781.       timer = gtk_timeout_add (get_frame_duration(frame_number),
  1782.                    (GtkFunction) advance_frame_callback, NULL);
  1783.     }
  1784.   else
  1785.     { /* STOP PLAYING */
  1786.       playing = FALSE;
  1787.       remove_timer();
  1788.     }
  1789. }
  1790.  
  1791. static void
  1792. rewind_callback (GtkWidget *widget,
  1793.          gpointer   data)
  1794. {
  1795.   if (playing)
  1796.     {
  1797.       playstop_callback(NULL, NULL); /* GTK weirdness workaround */
  1798.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psbutton), FALSE);
  1799.       playing = FALSE;
  1800.       remove_timer();
  1801.     }
  1802.  
  1803.   frame_number = 0;
  1804.   render_frame(frame_number);
  1805.   show_frame();
  1806. }
  1807.  
  1808. static void
  1809. step_callback (GtkWidget *widget,
  1810.            gpointer   data)
  1811. {
  1812.   if (playing)
  1813.     {
  1814.       playstop_callback(NULL, NULL); /* GTK weirdness workaround */
  1815.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psbutton), FALSE);
  1816.       playing = FALSE;
  1817.       remove_timer();
  1818.     }
  1819.  
  1820.   do_step();
  1821.   show_frame();
  1822. }
  1823.  
  1824.  
  1825.  
  1826.  
  1827.  
  1828. /* tag util. */
  1829.  
  1830. static DisposeType
  1831. get_frame_disposal (const guint whichframe)
  1832. {
  1833.   gchar* layer_name;
  1834.   DisposeType disposal;
  1835.   
  1836.   layer_name = gimp_layer_get_name(layers[total_frames-(whichframe+1)]);
  1837.   disposal = parse_disposal_tag(layer_name);
  1838.   g_free(layer_name);
  1839.  
  1840.   return(disposal);
  1841. }
  1842.  
  1843.  
  1844.  
  1845. static guint32
  1846. get_frame_duration (const guint whichframe)
  1847. {
  1848.   gchar* layer_name;
  1849.   gint   duration = 0;
  1850.  
  1851.   layer_name = gimp_layer_get_name(layers[total_frames-(whichframe+1)]);
  1852.   if (layer_name != NULL)
  1853.     {
  1854.       duration = parse_ms_tag(layer_name);
  1855.       g_free(layer_name);
  1856.     }
  1857.   
  1858.   if (duration < 0) duration = 100;  /* FIXME for default-if-not-said  */
  1859.   else
  1860.     if (duration == 0) duration = 100; /* FIXME - 0-wait is nasty */
  1861.  
  1862.   return ((guint32) duration);
  1863. }
  1864.  
  1865.  
  1866. static int
  1867. is_ms_tag (const char *str, int *duration, int *taglength)
  1868. {
  1869.   gint sum = 0;
  1870.   gint offset;
  1871.   gint length;
  1872.  
  1873.   length = strlen(str);
  1874.  
  1875.   if (str[0] != '(')
  1876.     return 0;
  1877.  
  1878.   offset = 1;
  1879.  
  1880.   /* eat any spaces between open-parenthesis and number */
  1881.   while ((offset<length) && (str[offset] == ' '))
  1882.     offset++;
  1883.   
  1884.   if ((offset>=length) || (!isdigit(str[offset])))
  1885.     return 0;
  1886.  
  1887.   do
  1888.     {
  1889.       sum *= 10;
  1890.       sum += str[offset] - '0';
  1891.       offset++;
  1892.     }
  1893.   while ((offset<length) && (isdigit(str[offset])));  
  1894.  
  1895.   if (length-offset <= 2)
  1896.     return 0;
  1897.  
  1898.   /* eat any spaces between number and 'ms' */
  1899.   while ((offset<length) && (str[offset] == ' '))
  1900.     offset++;
  1901.  
  1902.   if ((length-offset <= 2) ||
  1903.       (toupper(str[offset]) != 'M') || (toupper(str[offset+1]) != 'S'))
  1904.     return 0;
  1905.  
  1906.   offset += 2;
  1907.  
  1908.   /* eat any spaces between 'ms' and close-parenthesis */
  1909.   while ((offset<length) && (str[offset] == ' '))
  1910.     offset++;
  1911.  
  1912.   if ((length-offset < 1) || (str[offset] != ')'))
  1913.     return 0;
  1914.  
  1915.   offset++;
  1916.   
  1917.   *duration = sum;
  1918.   *taglength = offset;
  1919.  
  1920.   return 1;
  1921. }
  1922.  
  1923.  
  1924. static int
  1925. parse_ms_tag (const char *str)
  1926. {
  1927.   int i;
  1928.   int rtn;
  1929.   int dummy;
  1930.   int length;
  1931.  
  1932.   length = strlen(str);
  1933.  
  1934.   for (i=0; i<length; i++)
  1935.     {
  1936.       if (is_ms_tag(&str[i], &rtn, &dummy))
  1937.     return rtn;
  1938.     }
  1939.   
  1940.   return -1;
  1941. }
  1942.  
  1943.  
  1944. static int
  1945. is_disposal_tag (const char *str, DisposeType *disposal, int *taglength)
  1946. {
  1947.   if (strlen(str) != 9)
  1948.     return 0;
  1949.   
  1950.   if (strncmp(str, "(combine)", 9) == 0)
  1951.     {
  1952.       *taglength = 9;
  1953.       *disposal = DISPOSE_COMBINE;
  1954.       return 1;
  1955.     }
  1956.   else if (strncmp(str, "(replace)", 9) == 0)
  1957.     {
  1958.       *taglength = 9;
  1959.       *disposal = DISPOSE_REPLACE;
  1960.       return 1;
  1961.     }
  1962.  
  1963.   return 0;
  1964. }
  1965.  
  1966.  
  1967. static DisposeType
  1968. parse_disposal_tag (const char *str)
  1969. {
  1970.   DisposeType rtn;
  1971.   int i, dummy;
  1972.   gint length;
  1973.  
  1974.   length = strlen(str);
  1975.  
  1976.   for (i=0; i<length; i++)
  1977.     {
  1978.       if (is_disposal_tag(&str[i], &rtn, &dummy))
  1979.     {
  1980.       return rtn;
  1981.     }
  1982.     }
  1983.  
  1984.   return (DISPOSE_UNDEFINED); /* FIXME */
  1985. }
  1986.